package com.leenmvc.core.utils;

import com.leenmvc.core.utils.collection.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.text.DecimalFormat;
import java.util.*;

/**
 * 转换工具类
 *
 * @author leen
 */
public class ConvertUtils {


    private static Logger logger = LoggerFactory.getLogger(ConvertUtils.class);

    public static DecimalFormat decimalFormat = new DecimalFormat("#.##");

    /**
     * 将一种类型转换成另外一种类型
     *
     * @param source
     * @param target
     * @param <T>
     * @return
     */
    public static <T> T sourceToTarget(Object source, Class<T> target) {
        if (source == null) {
            return null;
        }
        T targetObject = null;
        try {
            targetObject = target.newInstance();
            BeanUtils.copyProperties(source, targetObject);
        } catch (Exception e) {
            logger.error("convert error ", e);
        }

        return targetObject;
    }

    /**
     * 将一个类转换成另外一种类型
     *
     * @param sourceList
     * @param target
     * @param <T>
     * @return
     */
    public static <T> List<T> sourceToTarget(Collection<?> sourceList, Class<T> target) {
        if (sourceList == null) {
            return null;
        }
        List targetList = new ArrayList<>(sourceList.size());
        try {
            for (Object source : sourceList) {
                T targetObject = target.newInstance();
                BeanUtils.copyProperties(source, targetObject);
                targetList.add(targetObject);
            }
        } catch (Exception e) {
            logger.error("convert error ", e);
        }

        return targetList;
    }

    /**
     * 获取对象中的字段值并将它置于Map中返回
     *
     * @param t
     * @param fields
     * @param <T>
     * @return
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static <T> Map entityToMap(T t, String... fields) {
        Class<?> cls = t.getClass();
        Map<String, Object> resultMap = null;

        resultMap = new HashMap<String, Object>();
        if (fields.length != 0) {
            for (String field : fields) {
                try {
                    Method declaredMethod = cls.getDeclaredMethod("get" + StringUtils.uppercaseFirstChar(field), null);
                    Object obj = declaredMethod.invoke(t, null);
                    getResultMap(resultMap, field, declaredMethod, obj);
                } catch (ReflectiveOperationException e) {
                    e.printStackTrace();
                }
            }
        } else if (fields.length == 0) {
            Field[] fs = cls.getDeclaredFields();
            Field[] parent = cls.getSuperclass().getDeclaredFields();
            for (Field field : fs) {
                try {
                    Method declaredMethod = cls.getDeclaredMethod("get" + org.apache.shiro.util.StringUtils.uppercaseFirstChar(field.getName()), null);
                    Object obj = declaredMethod.invoke(t, null);
                    getResultMap(resultMap, field.getName(), declaredMethod, obj);
                } catch (ReflectiveOperationException e) {
                    e.printStackTrace();
                }
            }
            // 父类中的字段
            for (Field field : parent) {
                try {
                    Method declaredMethod = cls.getSuperclass().getDeclaredMethod("get" + org.apache.shiro.util.StringUtils.uppercaseFirstChar(field.getName()), null);
                    Object obj = declaredMethod.invoke(t, null);
                    getResultMap(resultMap, field.getName(), declaredMethod, obj);
                } catch (ReflectiveOperationException e) {
                    e.printStackTrace();
                }
            }
        }
        return resultMap;
    }

    private static void getResultMap(Map<String, Object> resultMap, String field, Method declaredMethod, Object obj) {
        Class<?> returnType = declaredMethod.getReturnType();
        String name = returnType.getName();
        switch (name) {
            case "java.lang.String":
                resultMap.put(field, obj == null ? "" : obj);
                break;
            case "java.lang.Integer":
                resultMap.put(field, obj == null ? 0 : obj);
                break;
            case "java.lang.Long":
                resultMap.put(field, obj == null ? 0 : obj);
                break;
            case "java.lang.Float":
                resultMap.put(field, obj == null ? 0 : obj);
                break;
            case "java.lang.Double":
                resultMap.put(field, obj == null ? 0 : obj);
                break;
            case "java.lang.Short":
                resultMap.put(field, obj == null ? 0 : obj);
                break;
            case "java.lang.Boolean":

            default:
                resultMap.put(field, obj == null ? "" : obj);
        }
    }

    /**
     * 获取对象列表中的字段值并将它置于List<Map>中返回
     *
     * @param ts
     * @param fields
     * @param <T>
     * @return
     */
    public static <T> List<Map> entityListToMapList(List<T> ts, String... fields) {
        List<Map> list = new ArrayList<>();
        for (T t : ts) {
            list.add(entityToMap(t, fields));
        }
        return list;
    }

    /**
     * Map转化成entity
     *
     * @param <T>
     * @return
     */
    public static <T> T mapToEntity(Class<?> cls, Map<String, Object> params) {
        Object obj = null;
        try {
            obj = cls.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        for (String param : params.keySet()) {
            Field field = null;
            try {
                field = cls.getDeclaredField(param);
                Method method = cls.getDeclaredMethod("set" + StringUtils.uppercaseFirstChar(field.getName()), field.getType());
                Class<?> type = field.getType();
                switch (type.getName()) {
                    case "java.lang.String":
                        method.invoke(obj, String.valueOf(params.get(param)));
                        break;
                    case "java.lang.Integer":
                        method.invoke(obj, MapUtils.getInteger(params, param));
                        break;
                    case "java.lang.Long":
                        method.invoke(obj, MapUtils.getLong(params, param));
                        break;
                    case "java.lang.Float":
                        method.invoke(obj, MapUtils.getFloat(params, param));
                        break;
                    case "java.lang.Double":
                        method.invoke(obj, MapUtils.getDouble(params, param));
                        break;
                    case "java.lang.Boolean":
                    default:
                }
            } catch (ReflectiveOperationException e) {
                e.printStackTrace();
            }
        }
        return (T) obj;
    }

    /**
     * 转换类型
     *
     * @param t
     * @param <T>
     * @return
     */
    public static <T> Object convertType(T t, Class<?> targetType) {
        String simpleName = targetType.getSimpleName();
        switch (simpleName) {
            case "int":
                return Integer.parseInt(t.toString());
            case "long":
                return Long.parseLong(t.toString());
            case "short":
                return Short.parseShort(t.toString());
            case "byte":
                return Byte.parseByte(t.toString());
            case "float":
                return Float.parseFloat(t.toString());
            case "double":
                return Double.parseDouble(t.toString());
            case "Integer":
                return Integer.parseInt(t.toString());
            case "Long":
                return Long.parseLong(t.toString());
            case "Short":
                return Short.parseShort(t.toString());
            case "Byte":
                return Byte.parseByte(t.toString());
            case "Float":
                return Float.parseFloat(t.toString());
            case "Double":
                return Double.parseDouble(t.toString());
            case "String":
                return t.toString();
            case "Boolean":
                return t == null ? false : Boolean.parseBoolean(t.toString());
            case "Date":
                String thisCls = t.getClass().getSimpleName();
                switch (thisCls) {
                    case "String":
                        return DateUtils.parse(t.toString());
                    case "Timestamp":
                        return new Date(((Timestamp) t).getTime());
                    case "Date":
                        return (Date) t;
                }
            default:
                return null;
        }
    }

    /**
     * 把request的参数转换成map
     *
     * @param request
     * @return
     */
    public static Map<String, String> convertRequestParamsToMap(HttpServletRequest request) {
        Map<String, String> retMap = new HashMap<String, String>();

        Set<Map.Entry<String, String[]>> entrySet = request.getParameterMap().entrySet();

        for (Map.Entry<String, String[]> entry : entrySet) {
            String name = entry.getKey();
            String[] values = entry.getValue();
            int valLen = values.length;

            if (valLen == 1) {
                retMap.put(name, values[0]);
            } else if (valLen > 1) {
                StringBuilder sb = new StringBuilder();
                for (String val : values) {
                    sb.append(",").append(val);
                }
                retMap.put(name, sb.toString().substring(1));
            } else {
                retMap.put(name, "");
            }
        }

        return retMap;
    }

}
